#include"Log.hpp"
#include"Socket.hpp"
#include<iostream>
#include<memory>
#include<sys/select.h>
#include<vector>
using namespace Net_Work;

const static int defaultport=8888;
const static int nums=sizeof(fd_set)*8;

class SelectServer
{
public:
    void HandlerEvent(fd_set &rfd)
    {
        for(int i=0;i<nums;i++)
        {
            if (_rfds_array[i] == nullptr)
                continue;
            int fd=_rfds_array[i]->GetSocket();
            if (FD_ISSET(fd, &rfd))
            {
                if (fd==_listensock->GetSocket()) 
                {
                    std::string clientip;
                    uint16_t clientport;
                    Socket *sock = _listensock->AcceptConnection(&clientip, &clientport);
                    if (!sock)
                    {
                        lg.LogMessage(Error, "accept error\n");
                        return;
                    }
                    lg.LogMessage(Info, "客户端ip:%s 客户端端口号:%d 文件描述符:%d \n", clientip.c_str(), clientport, fd);

                    int pos = 0;
                    for (; pos < nums; pos++)
                    {
                        if (_rfds_array[pos] == nullptr)
                        {
                            _rfds_array[pos] = sock;
                            lg.LogMessage(Info,"get a new link: %d\n",sock->GetSocket());
                            break;
                        }
                    }

                    if (pos == nums)
                    {
                        _rfds_array[pos]->CloseSockfd();
                        delete sock;
                        lg.LogMessage(Warning, "select if full...\n");
                    }
                }
                else // 普通读事件就绪
                {
                    lg.LogMessage(Info,"The normal read event is ready\n");
                    std::string buffer;
                    if (_rfds_array[i]->Recv(&buffer, 1024))
                    {
                        lg.LogMessage(Info, "client say#: %s\n", buffer.c_str());
                        buffer.clear();

                    }
                    else
                    {
                        _rfds_array[i]->CloseSockfd();
                        delete _rfds_array[i];
                        _rfds_array[i]=nullptr;
                    }
                }
            }
        }
    }

    SelectServer(int defaultport)
        : _port(defaultport), _listensock(new TcpSocket), _isrunning(false)
    {}
    void InitServer()
    {
        _listensock->BuildListenSocketMethod(_port,backlog);
        for(int i=0;i<nums;i++)
        {
            _rfds_array[i]=nullptr;
        }
        _rfds_array[0]=_listensock.get();
    }
    void loop()
    {
        _isrunning=true;
        while(_isrunning)
        {
            fd_set rfds;
            FD_ZERO(&rfds);
            int max_fd=_listensock->GetSocket();
            for(int i=0;i<nums;i++)
            {
                if(_rfds_array[i]==nullptr)continue;
                else
                {
                    int fd=_rfds_array[i]->GetSocket();
                    FD_SET(fd,&rfds);
                    if(max_fd<fd) max_fd=fd;
                }
            }
            PrintDebug();
            struct timeval timeout{5,0};
            int n=select(max_fd+1,&rfds,nullptr,nullptr,nullptr);
            switch(n)
            {
                case 0:
                    lg.LogMessage(Debug,"select timeout...,last time: %u:%u\n",timeout.tv_sec,timeout.tv_usec);
                    break;
                case -1:
                    lg.LogMessage(Debug,"select error!!!,last time: %u:%u\n",timeout.tv_sec,timeout.tv_usec);
                    break;
                default:
                    lg.LogMessage(Debug,"select success,begin event handler,last time: %u:%u\n",timeout.tv_sec,timeout.tv_usec);
                    HandlerEvent(rfds);
                    break;
            }
        }
        _isrunning=false;
    }
    void stop()
    {
        _isrunning=false;
    }
    void PrintDebug()
    {
        std::cout<<"current selece rfds list is : ";
        for(int i=0;i<nums;i++)
        {
            if(_rfds_array[i]==nullptr)continue;
            else
            {
                std::cout<<_rfds_array[i]->GetSocket()<<" ";
            }
        }
        std::cout<<std::endl;
    }
    ~SelectServer(){}
private:
    std::unique_ptr<Socket> _listensock;
    int _port;
    int _isrunning;
    Socket* _rfds_array[nums];
};